/**
 * MCU 型号规格定义头文件
 * 张勇 / 41204@qq.com
 */

#pragma once

/// RAM 大小
#define MCU_RAM_SIZE 0
/// RAM 起始地址
#define MCU_RAM_BEGIN_ADDRESS
/// RAM 结束地址(有效区域为地址所指向的前一个字节)
#define MCU_RAM_END_ADDRESS		(MCU_RAM_BEGIN_ADDRESS + MCU_RAM_SIZE)

/// Flash 大小
#define MCU_FLASH_SIZE 0
/// Flash 起始地址
#define MCU_FLASH_BEGIN_ADDRESS 0x08000000
/// Flash 结束地址(有效区域为地址所指向的前一个字节)
#define MCU_FLASH_END_ADDRESS   (MCU_FLASH_BEGIN_ADDRESS + MCU_FLASH_SIZE)
/// Flash 页面大小
#define MCU_FLASH_PAGE_SIZE 2048

// 把统一定义的 gpio_intr_type_t 转换为 XScuGic_SetPriorityTriggerType() 中断触发类型
int scugic_intr_type(mcu_gpio_intr_type_t trig);
// 翻转 XScuGic 中断触发类型极性
int scugic_intr_type_toggle_polarity(uint8_t irq_type);

/**
 * Xilinx PS-GPIO 驱动适配层
 */
// 把统一定义的 gpio_intr_type_t 转换为 XGpioPs_SetIntrTypePin() 中断触发类型
int gpiops_intr_type(mcu_gpio_intr_type_t trig);
// 翻转 XGpioPs 中断触发类型极性
int gpiops_intr_type_toggle_polarity(uint8_t irq_type);

/// 端口配置
std_err_t GPIO_Config(uint16_t devid, uint16_t pin, mcu_gpio_mode_t mode);
/// 设置输出电平
std_err_t GPIO_SetLevel(uint16_t devid, uint16_t pin, uint8_t level);
/// 获取输入电平
uint8_t   GPIO_GetLevel(uint16_t devid, uint16_t pin);
/// GPIO 双向输入
uint8_t   GPIO_BidiIn(uint16_t devid, uint16_t pin);
/// GPIO 双向输出
std_err_t GPIO_BidiOut(uint16_t devid, uint16_t pin, uint8_t level);

/// 配置 PS-GPIO 中断
std_err_t GPIO_EXTI_Config(uint16_t devid, uint16_t pin, uint32_t irqn, uint8_t priority, mcu_gpio_intr_type_t trig, mcu_isr_t isr, void *cookie);
/// 使能/关闭中断
std_err_t GPIO_EXTI_Enable(uint16_t devid, uint16_t pin, uint32_t irqn, bool enable);
/// 翻转中断触发(边沿/电平)极性
std_err_t GPIO_EXTI_ToggleTrigPolarity(uint16_t devid, uint16_t pin, uint32_t irqn);
/// 判断对应引脚是否产生中断
bool      GPIO_EXTI_Flag(uint16_t devid, uint16_t pin);
/// 清除对应引脚中断标志位
std_err_t GPIO_EXTI_Clear(uint16_t devid, uint16_t pin);

/**
 * 定义命名的 GPIO APIs(基本的)
 */
#define GPIO_DEFINE(NAME, DEVID, PIN, IRQN) \
	static inline std_err_t  GPIO_##NAME##_Config(mcu_gpio_mode_t mode)   { return GPIO_Config(DEVID, PIN, mode); } \
	static inline uint8_t    GPIO_##NAME##_ReadIn(void)               { return GPIO_GetLevel(DEVID, PIN); } \
	static inline std_err_t  GPIO_##NAME##_Out(uint8_t x)             { return GPIO_SetLevel(DEVID, PIN, x); } \
	static inline uint8_t    GPIO_##NAME##_ReadOut(void)              { return GPIO_GetLevel(DEVID, PIN); } \
	static inline uint8_t    GPIO_##NAME##_BidiIn(void)               { return GPIO_BidiIn(DEVID, PIN); } \
	static inline std_err_t  GPIO_##NAME##_BidiOut(uint8_t x)         { return GPIO_BidiOut(DEVID, PIN, x); } \
	static inline std_err_t  GPIO_##NAME##_Toggle(void)               { return GPIO_SetLevel(DEVID, PIN, !GPIO_GetLevel(DEVID, PIN)); } \
	static inline std_err_t  GPIO_##NAME##_EXTI_Config(gpio_intr_type_t trig, mcu_isr_func_t isr, void *cookie) { return GPIO_EXTI_Config(DEVID, PIN, IRQN, trig, isr, cookie); } \
	static inline std_err_t  GPIO_##NAME##_EXTI_ToggleTrigPolarity()  { return GPIO_EXTI_ToggleTrigPolarity(DEVID, PIN, IRQN); } \
	static inline std_err_t  GPIO_##NAME##_EXTI_Enable()              { return GPIO_EXTI_Enable(DEVID, PIN, IRQN, true); } \
	static inline std_err_t  GPIO_##NAME##_EXTI_Disable()             { return GPIO_EXTI_Enable(DEVID, PIN, IRQN, false); } \
	static inline std_err_t  GPIO_##NAME##_EXTI_Flag(void)            { return GPIO_EXTI_Flag(DEVID, PIN); } \
	static inline std_err_t  GPIO_##NAME##_EXTI_Clear(void)           { return GPIO_EXTI_Clear(DEVID, PIN); }

/**
 * 定义命名的 GPIO APIs(带极性的)
 */
#define GPIO_DEFINE_POLARITY(NAME, DEVID, PIN, IRQN, ACTIVE_LEVEL) \
	GPIO_DEFINE(NAME, DEVID, PIN, IRQN) \
	static inline uint8_t   GPIO_##NAME##_Polarity(void)             { return ACTIVE_LEVEL; } \
	static inline std_err_t GPIO_##NAME##_On(void)                   { return GPIO_##NAME##_Out(ACTIVE_LEVEL); } \
	static inline std_err_t GPIO_##NAME##_Off(void)                  { return GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	static inline std_err_t GPIO_##NAME##_Switch(uint8_t on)         { return on ? GPIO_##NAME##_Out(ACTIVE_LEVEL) : GPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	static inline uint8_t   GPIO_##NAME##_IsInOn(void)               { return (GPIO_##NAME##_ReadIn() == ACTIVE_LEVEL); } \
	static inline uint8_t   GPIO_##NAME##_IsInOff(void)              { return (GPIO_##NAME##_ReadIn() != ACTIVE_LEVEL); } \
	static inline uint8_t   GPIO_##NAME##_IsOutOn(void)              { return (GPIO_##NAME##_ReadOut() == ACTIVE_LEVEL); } \
	static inline uint8_t   GPIO_##NAME##_IsOutOff(void)             { return (GPIO_##NAME##_ReadOut() != ACTIVE_LEVEL); }


/**
 * Xilinx PL/AXI-GPIO 驱动适配层
 *
 * 关于 AXI-GPIO
 * - 每个 AXI-GPIO 模块可能有 1~2 个 channel
 * - 每个 channel 可能有 1~32 个 pin
 * - 每个 AXI-GPIO 模块只有一条中断线(对应 GIC 的一个 IRQN)，由两个 channel 共享；
 * - 每个 AXI-GPIO 模块有一个全局的中断使能位
 * - 每个 channel 各有一个中断使能位、中断状态/清除位，由本 channel 内各个 pin 共享
 * - 每个 AXI-GPIO 模块的中断检测模块检测到任一 channel 的任一 pin 输入信号有变化时，会在 ip2intc_irpt 引脚输出一个 100 个周期左右的高电平脉冲信号
 * - 所以 GIC 检测 AXI-GPIO 中断时，只能采用上升沿触发
 */



/// 端口配置
std_err_t XGPIO_Config(uint16_t devid, uint16_t chid, uint16_t pin, mcu_gpio_mode_t mode);
/// 设置输出电平
std_err_t XGPIO_SetLevel(uint16_t devid, uint16_t chid, uint16_t pin, uint8_t level);
/// 获取输入电平
uint8_t   XGPIO_GetLevel(uint16_t devid, uint16_t chid, uint16_t pin);
/// 双向输入
uint8_t   XGPIO_BidiIn(uint16_t devid, uint16_t chid, uint16_t pin);
/// 双向输出
std_err_t XGPIO_BidiOut(uint16_t devid, uint16_t chid, uint16_t pin, uint8_t level);

/// 配置中断
std_err_t XGPIO_EXTI_Config(uint16_t devid, uint16_t chid, uint16_t pin, uint32_t irqn, uint8_t priority, mcu_isr_t isr, void *cookie);
/// 使能/关闭中断
std_err_t XGPIO_EXTI_Enable(uint16_t devid, uint16_t chid, uint16_t pin, uint32_t irqn, bool enable);
/// 判断对应引脚是否产生中断
bool      XGPIO_EXTI_Flag(uint16_t devid, uint16_t chid, uint16_t pin);
/// 清除对应引脚中断标志位
std_err_t XGPIO_EXTI_Clear(uint16_t devid, uint16_t chid);
/// 手动触发指定通道的中断
std_err_t XGPIO_EXTI_TrigMannually(uint16_t devid, uint16_t chid);

/**
 * 定义命名的 APIs(基本的)
 */
#define XGPIO_DEFINE(NAME, DEVID, CHID, PIN, IRQN) \
	static inline std_err_t XGPIO_##NAME##_Config(mcu_gpio_mode_t mode)  { return XGPIO_Config(DEVID, CHID, PIN, mode); } \
	static inline uint8_t   XGPIO_##NAME##_ReadIn(void)              { return XGPIO_GetLevel(DEVID, CHID, PIN); } \
	static inline std_err_t XGPIO_##NAME##_Out(uint8_t x)            { return XGPIO_SetLevel(DEVID, CHID, PIN, x); } \
	static inline uint8_t   XGPIO_##NAME##_ReadOut(void)             { return XGPIO_GetLevel(DEVID, CHID, PIN); } \
	static inline uint8_t   XGPIO_##NAME##_BidiIn(void)              { return XGPIO_BidiIn(DEVID, CHID, PIN); } \
	static inline std_err_t XGPIO_##NAME##_BidiOut(uint8_t x)        { return XGPIO_BidiOut(DEVID, CHID, PIN, x); } \
	static inline std_err_t XGPIO_##NAME##_Toggle(void)              { return XGPIO_SetLevel(DEVID, CHID, PIN, !XGPIO_GetLevel(DEVID, CHID, PIN)); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Config(uint8_t priority, mcu_isr_t isr, void *cookie) { return XGPIO_EXTI_Config(DEVID, CHID, PIN, IRQN, priority, isr, cookie); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Enable()             { return XGPIO_EXTI_Enable(DEVID, CHID, PIN, IRQN, true); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Disable()            { return XGPIO_EXTI_Enable(DEVID, CHID, PIN, IRQN, false); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Flag(void)           { return XGPIO_EXTI_Flag(DEVID, CHID, PIN); } \
	static inline std_err_t XGPIO_##NAME##_EXTI_Clear(void)          { return XGPIO_EXTI_Clear(DEVID, CHID); }

/**
 * 定义命名的 APIs(带极性的)
 */
#define XGPIO_DEFINE_POLARITY(NAME, DEVID, CHID, PIN, IRQN, ACTIVE_LEVEL) \
	XGPIO_DEFINE(NAME, DEVID, CHID, PIN, IRQN) \
	static inline uint8_t   XGPIO_##NAME##_Polarity(void)             { return ACTIVE_LEVEL; } \
	static inline std_err_t XGPIO_##NAME##_On(void)                   { return XGPIO_##NAME##_Out(ACTIVE_LEVEL); } \
	static inline std_err_t XGPIO_##NAME##_Off(void)                  { return XGPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	static inline std_err_t XGPIO_##NAME##_Switch(uint8_t on)         { return on ? XGPIO_##NAME##_Out(ACTIVE_LEVEL) : XGPIO_##NAME##_Out(!ACTIVE_LEVEL); } \
	static inline uint8_t   XGPIO_##NAME##_IsInOn(void)               { return (XGPIO_##NAME##_ReadIn()  == ACTIVE_LEVEL); } \
	static inline uint8_t   XGPIO_##NAME##_IsInOff(void)              { return (XGPIO_##NAME##_ReadIn()  != ACTIVE_LEVEL); } \
	static inline uint8_t   XGPIO_##NAME##_IsOutOn(void)              { return (XGPIO_##NAME##_ReadOut() == ACTIVE_LEVEL); } \
	static inline uint8_t   XGPIO_##NAME##_IsOutOff(void)             { return (XGPIO_##NAME##_ReadOut() != ACTIVE_LEVEL); }



/**
 * Xilinx PL/AXI-SPI 驱动适配层
 * 关于每个AXI-SPI 模块可能存在最多32个从机或主机
 * 一般不将FPGA侧的SPI实例作为从机，所以参数默认为master
 * 存在一个中断出口，目前尚未使用过spi的终端功能，暂不进行适配
 * AXI-SPI使用前需要进行配置，包括以下内容：
 * 	*搜寻设备ID进行初始化	XSpi_Initialize
 * 	*复位	XSpi_Reset
 * 	*配置主机模式，允许选择从机	XSpi_SetOptions 	XSP_MASTER_OPTION XSP_MANUAL_SSELECT_OPTION
 * 	*启动SPI设备	XSpi_Start
 * 	*禁用SPI全局中断功能	XSpi_IntrGlobalDisable 不禁用的话会存在控制问题，表现为CS不拉高
 *
 * 	*选择从机编号，这一步应该放到transfer函数中
 */
// 初始化函数
std_err_t	XSPI_CONFIG(uint8_t devid);
//spi传输函数
std_err_t	XSPI_TRX(uint8_t devid, uint8_t slave_id, uint8_t *tx, uint8_t *rx, size_t len, size_t *trxlen);

#define XSPI_DEFINE(NAME, DEVID)	\
	static inline std_err_t XSPI_##NAME##_Config()	{return XSPI_CONFIG(DEVID); }	\
	static inline std_err_t XSPI_##NAME##_TX(uint8_t slave_num, uint8_t *tx, size_t len, size_t *txlen) {return XSPI_TRX(DEVID, slave_num, tx, NULL, len, *txlen);}	\
	static inline std_err_t XSPI_##NAME##_RX(uint8_t slave_num, uint8_t *tx, uint8_t *rx, size_t len, size_t *rxlen) {return XSPI_TRX(DEVID, slave_num, tx, rx, len, *rxlen);}









